package com.tanhua.server.service;

import com.alibaba.fastjson.JSON;
import com.tanhua.autoconfig.templates.AipFaceTemplate;
import com.tanhua.autoconfig.templates.OssTemplate;
import com.tanhua.autoconfig.templates.SmsTemplate;
import com.tanhua.domain.db.User;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.mongo.Friend;
import com.tanhua.domain.mongo.UserLike;
import com.tanhua.dubbo.api.db.UserApi;
import com.tanhua.dubbo.api.db.UserInfoApi;
import com.tanhua.dubbo.api.mongo.FriendApi;
import com.tanhua.dubbo.api.mongo.UserLikeApi;
import com.tanhua.server.exceptions.TanhuaException;
import com.tanhua.server.interceptors.UserHolder;
import com.tanhua.server.utils.JwtUtils;
import com.tanhua.vo.CountsVo;
import com.tanhua.vo.PageResult;
import com.tanhua.vo.UserFriendVo;
import com.tanhua.vo.UserInfoVo;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class UserService {

    @Reference  //引用 关联
    private UserApi userApi;
    @Reference
    private UserInfoApi userInfoApi;
    @Reference
    private FriendApi friendApi;
    @Reference
    private UserLikeApi userLikeApi;

    @Autowired
    private SmsTemplate smsTemplate;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public ResponseEntity findByMobile(String mobile) {
        User user = userApi.findByMobile(mobile);
        return ResponseEntity.ok(user);
    }

    public ResponseEntity save(String telephone, String password) {
        User user = new User();
        user.setMobile(telephone);
//        user.setUpdated(new Date());
//        user.setCreated(new Date());
        user.setPassword(DigestUtils.md5Hex(password)); //这个密码其实用不到
        Long userId = userApi.save(user);
//        return ResponseEntity.ok(userId);
        return ResponseEntity.status(HttpStatus.CREATED).body(userId);
    }

    private static String prefix="CODE_";

    public ResponseEntity sendCode(String phone) throws Exception {

        //登录冻结
        User user = userApi.findByMobile(phone);
        if (user != null){
            Long userId = user.getId();
            UserInfo userInfo = userInfoApi.findById(userId);
            String userStatus = userInfo.getUserStatus();
            //暂时
            String freezingRange = redisTemplate.boundValueOps("FREEZE_KEY_"+userId.toString()).get();
            //永久
            String freezingRangePlus = redisTemplate.boundValueOps("FREEZEFOREVER_KEY_"+userId.toString()).get();
            //冻结创建时间
            String freezeCreated = redisTemplate.boundValueOps("freezeCreated" + userId.toString()).get();
            //冻结时间
            String freezingTime = redisTemplate.boundValueOps("freezingTime" + userId.toString()).get();
            //逻辑判断被冻结（1 冻结登录，2 冻结发言，3 冻结发布动态）
            if (freezingRange == null) {
                userInfoApi.updateById(userId);
            }
            //逻辑判断 如果用户状态等于2（“封禁”）
            //因为不涉及登录，所有排除登录封禁
            if (StringUtils.equals(userStatus,"2")){
                if (StringUtils.equals(freezingRange,"1")){
                    //直接显示冻结时间
                    throw new TanhuaException(500,"你的账户于"+freezeCreated+"，限制登录为期："+freezingTime+"天");
                }else if (StringUtils.equals(freezingRangePlus,"forever")){//或者为永久封禁
                    throw new TanhuaException(500,"你的账户被永久冻结");
                }
            }
        }

//        登录第一步---给手机号发送验证码
//        String randomNumeric = RandomStringUtils.randomNumeric(6); //TODO 上线时放开
        String randomNumeric = "123456";
//        smsTemplate.sendSms(phone,randomNumeric);  //TODO 上线时放开
        System.out.println(randomNumeric);
        redisTemplate.boundValueOps(prefix+phone).set(randomNumeric,5, TimeUnit.MINUTES);
        return ResponseEntity.ok(null);
    }

    public ResponseEntity loginVerification(String phone, String verificationCode) {
//        1、从redis中取值
        String randomNumeric = redisTemplate.boundValueOps(prefix + phone).get();
//                判断是否有值
        if(randomNumeric==null){
            throw new TanhuaException(1234,"验证码失效"); //文案
        }
//                如果有值判断是否相等
        if(!StringUtils.equals(verificationCode,randomNumeric)){
            throw new TanhuaException(1234,"验证码错误");
        }
//        2、根据手机号查询用户
        User user = userApi.findByMobile(phone);
//              如果查不到 插入一条新的用户数据

        boolean isNew = false;

        if(user==null){
            isNew = true;
            user = new User();
            user.setPassword(DigestUtils.md5Hex("123456")); //预留字段 这里先随便给一个默认值 0
//            user.setCreated(new Date());
//            user.setUpdated(new Date());
            user.setMobile(phone);

//            userApi.save(user);//这里有个坑
            Long userId = userApi.save(user);//这里有个坑
            user.setId(userId);
        }
//        3、把user通过jwt生成一个token字符串
        String token = JwtUtils.createToken(phone, user.getId(), "class154");
//        4、把这个字符串存到redis中，设置2个小时失效时间

//        需要根据token快速知道这个人是谁
//        把一个对象转成json字符串
        redisTemplate.boundValueOps("TOKEN_"+token).set(JSON.toJSONString(user),2,TimeUnit.HOURS);

//        5、构建返回的数据
//        {token:"",isNew:true}

        Map resultMap = new HashMap();
        resultMap.put("token",token);
        resultMap.put("isNew",isNew);


        Map map = new HashMap();
        map.put("userId",user.getId());
        map.put("type",isNew?"0102":"0101");  //0101为登录，0102为注册
        map.put("logTime", DateTime.now().toString("yyyy-MM-dd"));

//        向mq中发送消息
        rocketMQTemplate.convertAndSend("tanhua154-logs",map);

        return ResponseEntity.ok(resultMap);

    }

    public ResponseEntity loginReginfo(String token, UserInfo userInfo) {
//        向UserInfo表中插入数据

        User user = getUserByToken(token);
        userInfo.setId(user.getId());
//        userInfo.setUpdated(new Date());
//        userInfo.setCreated(new Date());

        userInfoApi.save(userInfo);

        return ResponseEntity.ok(null);



    }

    public User getUserByToken(String token) {
        String userStr = redisTemplate.boundValueOps("TOKEN_" + token).get();
        if(userStr==null){
            throw new TanhuaException(500,"请重新登录");
        }

//        给redis中token 续命
        redisTemplate.boundValueOps("TOKEN_"+token).set(userStr,2,TimeUnit.HOURS);

        return JSON.parseObject(userStr, User.class);
    }

    @Autowired
    private AipFaceTemplate aipFaceTemplate;
    @Autowired
    private OssTemplate ossTemplate;

    public ResponseEntity loginReginfoHead(String token, MultipartFile headPhoto) throws Exception {
//        1、百度ai判断是否为人脸
        boolean isFace = aipFaceTemplate.detect(headPhoto.getBytes());
        if(!isFace){
            throw new TanhuaException(500,"请重新拍照");
        }
//        2、如果是人脸 把图片上传到阿里云 返回一个url路径
        String avatarUrl = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());

//        3、更新tb_user_info表中的值
//        上传头像 更新userinfo表中的 avatar属性
//        update tb_user_info set avatar=? where id=?

        User user = getUserByToken(token);

        UserInfo userInfo = new UserInfo();
        userInfo.setId(user.getId());
        userInfo.setAvatar(avatarUrl);
//        userInfo.setUpdated(new Date());
        userInfoApi.update(userInfo);

        return ResponseEntity.ok(null);
    }

    public ResponseEntity findUserInfoById(Long id) {
//        根据id查询UserInfo
        UserInfo userInfo = userInfoApi.findById(id);
//      根据UserInfo转成UserInfoVo
        UserInfoVo userInfoVo = new UserInfoVo();

//        属性名称和数据类型必须一致才能拷贝
        BeanUtils.copyProperties(userInfo,userInfoVo); //源  目标
//        单独处理age
        if(userInfo.getAge()!=null){
            userInfoVo.setAge(userInfo.getAge().toString());
        }

        return ResponseEntity.ok(userInfoVo);

    }

    public ResponseEntity updateUserInfo(UserInfo userInfo) {

        Long userId = UserHolder.getUser().getId();
        userInfo.setId(userId);
//        update tb_user_info set ?=? where id=?
        userInfoApi.update(userInfo);
        return ResponseEntity.ok(null);
    }

    public ResponseEntity updateUserInfo(String token, UserInfo userInfo) {

        Long userId = getUserByToken(token).getId();
        userInfo.setId(userId);
//        update tb_user_info set ?=? where id=?
        userInfoApi.update(userInfo);
        return ResponseEntity.ok(null);
    }

    //eachLoveCount互相喜欢  loveCount喜欢  fanCount关注

    /**
     * 显示互相喜欢、喜欢、粉丝数量
     *
     * @return countsVo
     */
    public CountsVo queryCounts() {
        //获取当前登录人id
        Long userId = UserHolder.getUserId();
        //创建返回对象
        CountsVo countsVo = new CountsVo();
        //根据FriendApi查询好友列表人数 返回值 Integer类型 eachLoveCount
        Integer eachLoveCount = friendApi.queryCounts(userId);
        //往CountsVo中添加数据 eachLoveCount
        countsVo.setEachLoveCount(eachLoveCount);
        //根据userLikeApi查询喜欢人数  返回值 Integer类型 loveCount
        Integer loveCount = userLikeApi.queryLoveCounts(userId);
        //往CountsVo中添加数据 loveCount
        countsVo.setLoveCount(loveCount);
        //根据userLikeApi查询粉丝人数  返回值 Integer类型 loveCount
        Integer fanCount = userLikeApi.queryFanCounts(userId);
        //往CountsVo中添加数据  fanCount
        countsVo.setFanCount(fanCount);
        //返回实体类对象
        return countsVo;
    }

    /**
     * 点击 互相喜欢、喜欢、粉丝以及谁看过我要显示具体的人
     * <p>
     * 请求方式  GET
     * 请求路径 /users/friends/:type
     *
     * @param type     1.互相关注 2.我关注 3.粉丝
     * @param page     页码
     * @param pagesize 分页大小
     * @return PageResult
     */
    public PageResult queryFriends(String type, Integer page, Integer pagesize) {
        //获取当前登录人id
        Long userId = UserHolder.getUserId();
        //提前把PageResult提取出来
        PageResult pageResult = null;
        //创建List集合 参数 UserFriendVo
        List<UserFriendVo> list = new ArrayList<>();
        //首先判断type不为空 使用工具类StringUtils中的isNotBlank方法
        if (StringUtils.isNotBlank(type)) {
            //判断前端传过来type的数值 是否为 1(相互喜欢) string类型 使用工具类StringUtils中的equals方法
            if (StringUtils.equals("1", type)) {
                //type=1 查询mongo数据库中的friend表  调用friendApi 查询并分页 返回值pageResult 代表查询出来与当前登录人是好友的人
                pageResult = friendApi.queryContacts(userId, page, pagesize);
                //根据返回值pageResult 获取 其中返回的 Friend 集合
                List<Friend> friendList = (List<Friend>) pageResult.getItems();
                //遍历friendList集合
                for (Friend friend : friendList) {
                    //创建返回的对象 UserFriendVo
                    UserFriendVo userFriendVo = new UserFriendVo();
                    //获取friend中FriendId(与当前登录人是好友的id)
                    Long friendId = friend.getFriendId();
                    //根据获取出来的FriendId 调用userInfoApi 查询对应的人
                    UserInfo userInfo = userInfoApi.findById(friendId);
                    //调用BeanUtils工具类中的copyProperties快速封装
                    BeanUtils.copyProperties(userInfo, userFriendVo);
                    //手动添加userFriendVo中没有的数据
                    userFriendVo.setMatchRate(RandomUtils.nextInt(30, 99));
                    //调用friendApi查询是否喜欢 返回值boolean
                    boolean alreadyLove = friendApi.queryLove(userId);
                    //手动给userFriendVo添加数据
                    userFriendVo.setAlreadyLove(alreadyLove);
                    //往list中添加数据
                    list.add(userFriendVo);
                }
                //判断前端传过来type的数值 是否为 2(喜欢) string类型 使用工具类StringUtils中的equals方法
            } else if (StringUtils.equals("2", type)) {
                //type=2 查询mongo数据库中的user_like表  userLikeApi 查询并分页 返回值pageResult
                pageResult = userLikeApi.queryToLike(userId, page, pagesize);
                //根据返回值pageResult 获取 其中返回的 UserLike 集合
                List<UserLike> userLikeList = (List<UserLike>) pageResult.getItems();
                //遍历userLikeListt集合
                for (UserLike userLike : userLikeList) {
                    //创建返回的对象 UserFriendVo
                    UserFriendVo userFriendVo = new UserFriendVo();
                    //获取userLike中LikeUserId
                    Long likeUserId = userLike.getLikeUserId();
                    //根据获取出来的likeUserId 调用userInfoApi 查询对应的人
                    UserInfo userInfo = userInfoApi.findById(likeUserId);
                    //调用BeanUtils工具类中的copyProperties快速封装
                    BeanUtils.copyProperties(userInfo, userFriendVo);
                    //手动添加userFriendVo中没有的数据
                    userFriendVo.setMatchRate(RandomUtils.nextInt(30, 99));
                    //调用userLikeApi查询是否喜欢 返回值boolean
                    boolean alreadyLove = userLikeApi.queryLike(userId, likeUserId);
                    //手动给userFriendVo添加数据
                    userFriendVo.setAlreadyLove(alreadyLove);
                    //往list中添加数据
                    list.add(userFriendVo);
                }
                //判断前端传过来type的数值 是否为 3(粉丝) string类型 使用工具类StringUtils中的equals方法
            } else if (StringUtils.equals("3", type)) {

                //type=3 查询mongo数据库中的user_like表  userLikeApi 查询并分页 返回值pageResult
                pageResult = userLikeApi.queryContacts(UserHolder.getUserId(), page, pagesize);
                //根据返回值pageResult 获取 其中返回的 UserLike 集合
                List<UserLike> userLikeList = (List<UserLike>) pageResult.getItems();
                //遍历userLikeListt集合
                for (UserLike userLike : userLikeList) {
                    //创建返回的对象 UserFriendVo
                    UserFriendVo userFriendVo = new UserFriendVo();
                    //获取userLike中的UserId
                    Long likeUserId = userLike.getUserId();
                    //根据获取出来的UserId 调用userInfoApi 查询对应的人
                    UserInfo userInfo = userInfoApi.findById(likeUserId);
                    //调用BeanUtils工具类中的copyProperties快速封装
                    BeanUtils.copyProperties(userInfo, userFriendVo);
                    //手动添加userFriendVo中没有的数据
                    userFriendVo.setMatchRate(RandomUtils.nextInt(30, 99));
                    //调用userLikeApi查询是否喜欢 返回值boolean
                    boolean alreadyLove = userLikeApi.queryLike(userId, likeUserId);
                    //手动给userFriendVo添加数据
                    userFriendVo.setAlreadyLove(alreadyLove);
                    //往list中添加数据
                    list.add(userFriendVo);
                }
            }

        }
        //往pageResult中添加数据
        pageResult.setItems(list);
        //返回pageResult
        return pageResult;
    }

    /**
     * 取消喜欢
     * <p>
     * 请求方式  DELETE
     * 请求路径 /users/like/:uid
     *
     * @param deleteId 要删除的用户id
     * @return 无
     */
    public ResponseEntity deleteLike(Long deleteId) {
        //获取当前登录人的id
        Long userId = UserHolder.getUserId();
        //调用friendApi查询两人是否是好友
        boolean friend = friendApi.queryToLike(userId, deleteId);
        //调用userLikeApi查询当前登录人 在mongo中的user_like表中有没有数据
        boolean userLike = userLikeApi.findLike(userId, deleteId);
        //判断friend  为true
        if (friend) {
            //根据userId和deleteId 调用friendApi 删除表中的数据
            friendApi.deleteLike(userId, deleteId);
            //根据userId和deleteId userLikeApi 删除表中的数据
            userLikeApi.deleteLike(userId, deleteId);
        } else if (userLike) {
            //先删除user_like表中的数据
            userLikeApi.deleteLike(userId, deleteId);
            //如果双方是好友
            if (friend) {
                //再删除friend表中数据
                friendApi.deleteLike(userId, deleteId);
            }
        }

        //返回数据为空
        return ResponseEntity.ok(null);
    }

    /**
     * 添加喜欢
     * <p>
     * 请求方式  POST
     * 请求路径 /users/fans/:uid
     *
     * @param likeId 添加喜欢用户的id
     * @return 无
     */
    public ResponseEntity fans(Long likeId) {
        //获取当前登录人的id
        Long userId = UserHolder.getUserId();
        //调用userLikeApi保存数据
        userLikeApi.save(userId, likeId);
        //调用friendApi保存数据
        friendApi.save(userId, likeId);
        //返回空
        return ResponseEntity.ok(null);

    }

    //修改手机号 - 2.校验验证码
    //校验验证码
    public ResponseEntity checkCode(String mobile, String code) {
        //1、获取redis中存入的验证码
        String value = redisTemplate.opsForValue().get(prefix+mobile);
        //2、判断redis中的验证码是否存在并比较验证码是否一致
        boolean bool = true;
        if(value == null || !value.equals(code)) {
            bool=false;
        }else {
            redisTemplate.delete(prefix+mobile) ;
        }
        //3、构造返回值
        Map<String, Object> result = new HashMap<>();
        result.put("verification", bool);
        return ResponseEntity.ok(result);
    }

    //修改手机号 - 3.保存
    //保存新的手机号
    public ResponseEntity<Void> saveNewMobile(String mobile) {
        //获取当前操作用户
        User user = UserHolder.getUser();
        //判断新手机号是否已经注册
        User exist = userApi.findByMobile(mobile);
        if(exist != null) {
            throw new TanhuaException(500, "请重新注册");
            //或者抛个异常
        }

        //验证手机号长度
        if(mobile.length() != 11){
            throw new TanhuaException(500, "手机号应为11位数，请重新注册");
        }

        //验证手机号格式
        String regex = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(17[013678])|(18[0,5-9]))\\d{8}$";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(mobile);
        boolean isMatch = m.matches();
        if(isMatch){
            //绑定更新
            user.setMobile(mobile);
            userApi.update(user);
            return ResponseEntity.ok(null);
        }else {
            throw new TanhuaException(500, "手机号格式错误，请重新注册");
        }

        //绑定更新
//        user.setMobile(mobile);
//        userApi.update(user);
//        return ResponseEntity.ok(null);
    }
}
